package com.tjbank.cssys.framework.base.util;

import java.util.regex.Pattern;

/**
 * 校验身份证号
 * 
 * Package : com.tansun.magicube.framework.base.util
 * 
 * @author -- lijiangtao 2020年4月7日 下午4:34:23
 *
 */
public class VerifyIDNumber {

    public static final Pattern REX_DATE_YYYYMM_PATTERN = Pattern.compile("^[0-9]{6}$");
    public static final Pattern REX_DATE_YYYYMMDD_PATTERN = Pattern.compile("^[0-9]{8}$");

    // 身份证校验加权因子
    public static final Integer[] ID_NUM_FACTOR = new Integer[] { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1 };

    // 身份证第18位校验码
    public static final String[] ID_NUM_PARITY_BIT = new String[] { "1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2" };

    /*
     * 是否空字符串
     * 
     * @param c 文本或其它基本数字类型对象
     */
    public static boolean isEmpty(Object c) {
        return c == null || c.toString().trim().equals("");
    }

    /**
     * 判断是否为“”式的时期
     * 
     * @param dateStr
     * @return
     */
    private static boolean isDate6(String dateStr) {
        if (isEmpty(dateStr) || !REX_DATE_YYYYMM_PATTERN.matcher(dateStr).matches()) {
            return false;
        }
        return isValidDateRange(date6Split(dateStr));
    }

    /**
     * 判断是否为“YYYYMMDD”式的时期
     * 
     * @param dateStr
     * @return
     */
    private static boolean isDate8(String dateStr) {
        if (isEmpty(dateStr) || !REX_DATE_YYYYMMDD_PATTERN.matcher(dateStr).matches()) {
            return false;
        }
        return isValidDateRange(date8Split(dateStr));
    }

    private static boolean isLeapYear(Integer year) {
        return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
    }

    private static boolean isInvalidYear(Integer year) {
        return year < 1700 || year > 2500;
    }

    private static boolean isInvalidMonth(Integer month) {
        return month < 1 || month > 12;
    }

    private static boolean isInvalidDay(Integer day, Integer month, Integer year) {
        Integer[] iaMonthDays = new Integer[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
        if (isLeapYear(year))
            iaMonthDays[1] = 29;
        return day < 1 || day > iaMonthDays[month - 1];
    }

    /**
     * split date 0-YY,1-MM,2-DD
     * 
     * @param dateStr
     * @return
     */
    private static Integer[] date6Split(String dateStr) {
        final Integer YEAR_BASE = 1900;
        Integer year = null, month = null, day = null;

        year = YEAR_BASE + Integer.valueOf(dateStr.substring(0, 2));
        month = Integer.valueOf(dateStr.substring(2, 4));
        day = Integer.valueOf(dateStr.substring(4, 6));
        return new Integer[] { year, month, day };
    }

    /**
     * split date 0-YYYY,1-MM,2-DD
     * 
     * @param dateStr
     * @return
     */
    private static Integer[] date8Split(String dateStr) {
        Integer year = null, month = null, day = null;

        year = Integer.valueOf(dateStr.substring(0, 4));
        month = Integer.valueOf(dateStr.substring(4, 6));
        if (dateStr.length() == 8) {
            day = Integer.valueOf(dateStr.substring(6, 8));
            return new Integer[] { year, month, day };
        } else {
            return new Integer[] { year, month };
        }
    }

    private static boolean isValidDateRange(Integer[] dateSplitResult) {
        Integer year = dateSplitResult[0], month = dateSplitResult[1], day = dateSplitResult[2];
        if (isInvalidYear(year))
            return false;
        if (isInvalidMonth(month))
            return false;
        if (isInvalidDay(day, month, year))
            return false;
        return true;
    }

    /**
     * 18位/15位身份证号码校验
     * 
     * @param idNumber
     * @return
     */
    public static boolean isIdentityCardNum(String idNumber) {
        if (isEmpty(idNumber) || (idNumber.length() != 18 && idNumber.length() != 15)) {
            return false;
        }
        if (idNumber.length() == 18) {
            String date8 = idNumber.substring(6, 14);
            if (isDate8(date8) == false) {
                return false;
            }
            int totalMulAiWi = 0;
            char charAt;
            for (int i = 0; i < 17; i++) {
                charAt = idNumber.charAt(i);
                if (charAt < '0' || charAt > '9') {
                    return false;
                }
                totalMulAiWi += Integer.valueOf(String.valueOf(charAt)) * ID_NUM_FACTOR[i];
            }

            String checkDigit = ID_NUM_PARITY_BIT[totalMulAiWi % 11];
            if (!checkDigit.equalsIgnoreCase(String.valueOf(idNumber.charAt(17)))) {
                return false;
            }
        } else {
            // length is 15
            // check date
            String date6 = idNumber.substring(6, 12);
            if (isDate6(date6) == false) {
                return false;
            }
        }
        return true;
    }
}
